package UIFree.controls
{
	import UIFree.ObjectEvent;
	import UIFree.uif_component;
	import UIFree.uif_ecomponent;
	
	import UIUtils.MouseWheel;
	
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Rectangle;
	import flash.utils.Timer;

	public class uif_hscrollArea extends uif_ecomponent {
		private var _list: Array;
		private var _startIndex: int;
		private var _bleft: uif_button;
		private var _bright: uif_button;
		private var _mask: uif_component;
		private var _rows: int;
		protected var _scroll: uif_ecomponent;
		protected var _containerWidth: int;
		private var _selectIndex: int;
		private var _selectItem: Object;
		private var _autoScrollTimer: Timer;
		private var _autoScrollInc: int;
		private var _autoScrollWait: int;
		private var _scrollStep: int;
		
		public var multiselect: Boolean;
		public static var DELAY_AUTO_SCROLL: int = 400;
		public static var WAIT_AUTO_SCROLL: int = 2;
		
		public var compareFunc: Function;
		
		public function uif_hscrollArea(parent:uif_component, ax:int=0, ay:int=0, awidth:int=0, 
										aheight:int=0, styleClass:String='', a_bwidth:int=0, wheelScrolling: Boolean=false) {
			super(parent, ax, ay, awidth, aheight, styleClass);
			_scrollStep	= 1;
			multiselect = false;
			_selectIndex = -1;
			_rows = 1;
			var bwidth: int = a_bwidth?a_bwidth:
								(style.arrowWidth?style.arrowWidth:aheight / 3);
			var inner: Rectangle = getInner();
			var cinn: Rectangle = getInner();
			cinn.inflate(-bwidth, 0);
			
			_scroll = new uif_ecomponent(this, cinn.x, cinn.y, cinn.width, cinn.height, style['area']);
			_mask = new uif_component(this, cinn.x, cinn.y, cinn.width, cinn.height, 'white');
			_scroll.mask = _mask;
			
			_bleft  = new uif_hscrollButon(this, inner.x, (aheight - bwidth) / 2, bwidth, bwidth, 4, style['arrow']);
			_bright = new uif_hscrollButon(this, inner.x + inner.width - bwidth, (aheight - bwidth) / 2, bwidth, bwidth, 2, style['arrow']);
			_bleft.setVisibility(false);
			_bright.setVisibility(false);
			
			_bleft.addEvent(MouseEvent.MOUSE_DOWN, function(e: MouseEvent): void {
				beginScroll(rows * scrollStep);
			});
			_bright.addEvent(MouseEvent.MOUSE_DOWN, function(e: MouseEvent): void {
				beginScroll(-rows * scrollStep);
			});
			addEvent(MouseEvent.MOUSE_UP, endScroll, app);
			
			_autoScrollTimer = new Timer(DELAY_AUTO_SCROLL);
			_autoScrollTimer.addEventListener(TimerEvent.TIMER, doAutoScroll);
			updateButtons();
			if (wheelScrolling) {
				addEvent(MouseEvent.MOUSE_WHEEL, doWhell);
				addEvent(MouseEvent.ROLL_OVER, doOver);
				addEvent(MouseEvent.ROLL_OUT, doOut);
			}
		}
		
		protected function beginScroll(a_scrollTo: int): void {
			scrollTo(a_scrollTo);
			_autoScrollInc	= a_scrollTo;
			_autoScrollWait	= 0;
			_autoScrollTimer.start();
		}
		
		public function get scrollStep(): Number {
			return _scrollStep;
		}
		
		public function set scrollStep(a_value: Number): void {
			_scrollStep = a_value;
		}
		
		protected function doAutoScroll(e: TimerEvent): void {
			if (_autoScrollInc != 0) {
				if (_autoScrollWait < WAIT_AUTO_SCROLL) _autoScrollWait++;
				else scrollTo(_autoScrollInc);
			}
		}
		
		protected function endScroll(e: Event=null): void {
			if (_autoScrollTimer.running) _autoScrollTimer.stop();
		}
		
		protected function doWhell(e: MouseEvent): void {
			scrollTo(Math.round(e.delta / 3));
			e.stopPropagation();
		}
		
		protected function doOver(e: Event): void {
			MouseWheel.capture();
		}
		
		protected function doOut(e: Event): void {
			MouseWheel.release();
		}
		
		protected function updateButtons(): void {
			function updateButton(button: uif_component, a_scrollTo: int): void {
				button.disable = !checkScroll(a_scrollTo);
			}
			updateButton(_bleft, 1);
			updateButton(_bright, -1);
		}
		
		public function assignList(list: Array, a_containerWidth: int, 
									createElem: Function, a_rows: int = 1, clearPos: Boolean = true): void {
			if (!list) list = [];
			_selectIndex = -1;
			if (clearPos) _startIndex = 0;
			_list = new Array();
/*			
			for each (var item: Object in list)
				_list.push({control:null, object:item});
*/			
			for (var i:int=0; i<list.length; i++)
				_list.push({control:null, object:list[i]});
			_containerWidth = a_containerWidth;
			_rows = a_rows; 
			refresh(createElem);
		}
		
		protected function calcAreaPos(leftIndex: int): Number {
			return _mask.x + Math.ceil(leftIndex / rows) * _containerWidth;
		}
		
		public function scrollTo(a_sctollTo: int): void {
			var sr: int = Math.ceil(scrollRightCount / rows) * rows;
			var sl: int = scrollLeftCount;
			
			if ((a_sctollTo < 0) && (-a_sctollTo > sr))
				a_sctollTo = -sr;
			else if ((a_sctollTo > 0) && (a_sctollTo > sl))
				a_sctollTo = sl;
			
			if (a_sctollTo != 0) {
				_scroll.fx('x', _scroll.x, calcAreaPos(_startIndex + a_sctollTo)).start(function(): void {
					updateButtons();
					dispatchEvent(new Event(Event.SCROLL));
				});
				_startIndex += a_sctollTo;
			}
		}
		
		public function get rows(): int {
			return _rows;
		}
		
		public function get countDisplay(): int {
			return Math.round(_mask.width / _containerWidth) * rows;
		}
		
		public function get scrollLeftCount(): int {
			return -_startIndex;
		}
		
		public function get scrollRightCount(): int {
			return _list.length + (_startIndex - countDisplay);
		}
		
		public function checkScroll(a_sctollTo: int): Boolean {
			return _list && ((_startIndex + a_sctollTo <= 0) &&
							 (_startIndex + a_sctollTo + Math.ceil(_list.length / rows) * rows >= countDisplay)); 
		}
		
		public function get items(): Array {
			return _list;
		}
		
		public function findControl(control: uif_component): int {
			for (var i: int =0; i< _list.length; i++)
				if (_list[i].control == control) return i;
			return -1; 
		}
		
		public function findObject(checkFunc: Function): int {
			for (var i: int =0; i< _list.length; i++)
				if (checkFunc(_list[i].object)) return i;
			return -1; 
		}
		
		public function get scrollArea(): uif_ecomponent {
			return _scroll;
		}
		
		public function get selectIndex(): int {
			return _selectIndex;			
		}
		
		public function checkVisible(index: int): Boolean {
			//index = Math.floor(index / rows) * rows;
			var s: int = -startIndex;
			return ((index >= s) && (index <= s + countDisplay));
		}
		
		public function set startIndex(a_left: int): void {
			if (_startIndex != a_left) {
				if (-a_left + countDisplay > _list.length) {
					a_left = -(_list.length - countDisplay);
					if (a_left > 0) a_left = 0;
				}
				_startIndex = Math.ceil(a_left / rows) * rows;
				_scroll.x = calcAreaPos(_startIndex);
				dispatchEvent(new Event(Event.SCROLL));
				updateButtons();
			}
		}
		
		public function get startIndex(): int {
			return _startIndex;			
		}
		
		public function set selectIndex(a_index: int): void {
			if ((_selectIndex != a_index) && (a_index >= -1) && (a_index < _list.length)) {
				doChangeIndex(a_index);
				if (a_index > -1) {
					if (a_index < -startIndex) startIndex = -a_index;
					else if (a_index >= Math.ceil((countDisplay - startIndex) / rows) * rows) 
						startIndex = countDisplay - a_index - rows;
				}
			}
			dispatchEvent(new ObjectEvent(Event.SELECT, selectItem));
		}
		
		protected function doChangeIndex(a_index: int): void {
			//if ((_selectIndex > -1) && !multiselect) items[_selectIndex].select = false;
			_selectIndex = a_index;
			if ((_selectIndex > -1) && multiselect) items[_selectIndex].select = true;
			doChangeItem(items[selectIndex]);
		}
		
		protected function doChangeItem(item: Object): void {
			if (item != _selectItem) {
				if (_selectItem && !multiselect) updateUnselectItem(_selectItem);
				_selectItem = item;
				if (_selectItem) updateSelectItem(_selectItem);
				dispatchEvent(new Event(Event.CHANGE));
			}
		}
		
		protected function get selectStyle(): Object {
			return app.styleByObj(style['select']);
		}
		
		protected function get unselectStyle(): Object {
			return app.styleByObj(style['unselect']);
		}
		
		public function deselectAll(): void {
			items.forEach(function(item: Object, i:int, arr: Array): void {
				if (item.select) {
					item.control.style = unselectStyle;
					item.select = false;
				}
			});
		}
		
		public function get selectList(): Array {
			var result: Array = new Array();
			items.forEach(function(item: Object, i:int, arr: Array): void {
				if (item.select) result.push(item.object);
			});
			return result;
		}
		
		protected function updateUnselectItem(a_unselectItem: Object): void {
			if (style['unselect'] && a_unselectItem.control) selectMethod(a_unselectItem, unselectStyle);
		}
		
		protected function updateSelectItem(a_selectItem: Object): void {
			if (style['select'] && a_selectItem.control) selectMethod(a_selectItem, selectStyle);
		}
		
		protected function selectMethod(a_selectItem: Object, a_style: Object): void {
			a_selectItem.control.style = a_style;
		}
		
		public function get selectItem(): Object {
			return _selectItem;
		}
		
		protected function createElement(c_func: Function, inner: Rectangle, i: int): uif_component {
			var item: uif_component = c_func(_scroll, inner, i);
			if (item) {
				item.addEventListener(MouseEvent.CLICK, function(e: Event): void {
					selectIndex = i;
				});
			} 
			return item;
		}
		
		public function get displayRect(): Rectangle {
			return _mask.getOuter();
		}
		
		public function calcFrameWidth(a_rows: int=0): Number {
			var dr: Rectangle 	= displayRect;
			var a: Number 		= dr.width / dr.height * (a_rows?a_rows:rows);
			return dr.width / (a>1?Math.floor(a):1);
		}
		
		protected function refresh(createElem: Function): void {
			if (_selectItem) _selectItem.control = null;
			_scroll.disposeChilds();
			while (!checkScroll(0) && (_startIndex < 0)) 
				_startIndex++;
			
			_scroll.x 	= _mask.x + _startIndex * _containerWidth;
			var inner: Rectangle = _scroll.getInner();
			
			inner.width = _containerWidth;
			inner.height = inner.height / rows;
			
			var _x: int=0;
			var _y: int=0;
			for (var i:int=0; i<_list.length; i++) {
				_list[i].control = createElement(createElem, inner.clone(), i);
				if ((compareFunc != null) && _selectItem && (compareFunc(_list[i].object, _selectItem.object))) {
					_list[i].control.style = app.styleByObj(style['select']);
					_selectItem 	= _list[i];
					_selectIndex 	= i; 
				} else if (!_list[i].control.styleClass) _list[i].control.styleClass = style['unselect'];
				_y++;
				if (_y == rows) {
					_x++;
					_y = 0;
					inner.y = _scroll.getInner().y;
					inner.x += _containerWidth;
				} else {
					inner.y += _list[i].control.height;
				}
			}
			_scroll.width = (_list.length / rows) * _containerWidth;
			updateButtons();
		}
	}
}